package com.picturehistory.core.jersey.services;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;

import com.picturehistory.core.jersey.dao.ArticleDAO;
import com.picturehistory.core.jersey.dao.UserDAO;
import com.picturehistory.core.jersey.exception.InvalidArgException;
import com.picturehistory.core.jersey.exception.InvalidKeyException;
import com.picturehistory.core.jersey.exception.InvalidPinException;
import com.picturehistory.core.jersey.exception.InvalidUserException;
import com.picturehistory.core.jersey.model.Article;
import com.picturehistory.core.jersey.model.User;
import com.picturehistory.core.jersey.resources.ArticleResource;

@Service
public class ArticleService {
	final Logger logger = LoggerFactory.getLogger(ArticleResource.class);
	
	@Autowired
	private ArticleDAO dao;
	
	@Autowired
	private UserDAO userDao;
	
	public ArticleService() {}
	
	public ArticleService(ArticleDAO dao) {
		this.dao = dao;
	}

	/*
	 * 
	 */
	private User validateUser(String user, String pin) 
	throws InvalidUserException, InvalidPinException {
		User persistentUser = null;
		try {
			persistentUser = userDao.getDetachedUserByUserId(user);
		} catch (DataAccessException e) {
			throw new InvalidUserException("there is no user identified by : " + user);
		}
		
		if (persistentUser == null) {
			throw new InvalidUserException("there is no user identified by : " + user);
		}
		if (!persistentUser.isActive()) {
			throw new InvalidUserException("user is not active");
		}
		
		if (!persistentUser.authenticate(pin)) {
			throw new InvalidUserException("cannot authenticate user");
		}
		return persistentUser;
	}
	
	/*
	 * 
	 */
	public void storeArticle(String user, String pin, Article at) 
	throws InvalidUserException, InvalidPinException {
		
		User persistentUser = validateUser(user, pin);
		
		long generatedId = dao.storeArticle(persistentUser, at);
	
		persistentUser.getArticles().add(new Long(generatedId));
		userDao.storeUser(persistentUser);
	}
	
	/*
	 * 
	 */
	public Article getArticleById(long id) {
		Article ret = null;
		try {
			ret = dao.getArticleById(id);
		} catch (DataAccessException e) {
			logger.info("Error Occured!!!! I think there's no mathing Article object with id=" + id);
			return null;
		}
		
		return ret;
	}
	
	/*
	 * 
	 */
	public Article updateArticle(String user, long id, String pin, Article at) 
	throws InvalidUserException, InvalidPinException, InvalidKeyException {
		
		logger.info("updateArticle(user=" + user + ", id=" + id + ", pin=" + pin + ", at=" + at + ")");
		
		User persistentUser = validateUser(user, pin);
		
		logger.info("user has been validated");
		
		Article target = null;
		try {
			target = dao.getArticleById(id);
		} catch (Exception e) {
			target = null;
		}
		
		if (target == null) {
			throw new InvalidKeyException(
					"InvalidKeyException: there is no article with key=" + id);
		}
		if (!(target.getAuthor().equals(persistentUser.getUserId()))) {
			logger.info("NotAnAuthor: user=" + user +
					" has no permission to modify this article=" + id);
			throw new InvalidUserException(
					"NotAnAuthor: user=" + user +
					" has no permission to modify this article=" + id);
		}
		if (!persistentUser.getArticles().contains(id)) {
			logger.info("DoesNotHaveAnArticle: user=" + user + 
					" has no permission to modify this article=" + id);
			throw new InvalidUserException(
					"DoesNotHaveAnArticle: user=" + user + 
					" has no permission to modify this article=" + id);
		}
		
		
		Article ret = dao.updateArticle(persistentUser, at, id);
		
		logger.info("article has been updated");
		
		return ret;
	}
	
	
	
	
	/*
	 * Testing
	 */
	public List<Article> loadArticleByXY(Integer x, Integer y) {
		List<Article> ret = null;
		try {
			logger.info("loading an article(s) with [x,y] = [" + x + "," + y + "]");
			ret = dao.loadArticleByXY(x, y);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return ret;
	}



}
